package com.battery.minapp.controller;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.response.AlipayFundAuthOperationDetailQueryResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.battery.common.enums.OrderTradeStateEnum;
import com.battery.common.utils.BatteryJSONResult;
import com.battery.common.utils.ali.AliPayEntity;
import com.battery.common.utils.ali.AliPayUtils;
import com.battery.minapp.config.properties.AliPayResource;
import com.battery.system.domain.AuthUsed;
import com.battery.system.domain.Order;
import com.battery.system.service.battery.IAuthUsedService;
import com.battery.system.service.battery.IOrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;


/**
 * 支付宝回调
 */
@Controller
@RequestMapping("/ali")
public class AliNotifyController {


    private static Logger logger = LoggerFactory.getLogger(AliNotifyController.class);


    @Autowired
    private IOrderService orderService;


    @Autowired
    private AliPayResource aliPayResource;


    @Autowired
    private IAuthUsedService authUsedService;


    private AliPayEntity _callApi() {
        AliPayEntity entity = new AliPayEntity();
        entity.setAppId(aliPayResource.getAppId());
        entity.setAlipayPublicKey(aliPayResource.getAlipayPublicKey());
        entity.setCharset(aliPayResource.getCharset());
        entity.setGatewayUrl(aliPayResource.getGatewayUrl());
        entity.setMerchantPrivateKey(aliPayResource.getMerchantPrivateKey());
        entity.setSignType(aliPayResource.getSignType());
        entity.setNotifyUrl(aliPayResource.getNotifyUrl());
        entity.setPayeeLogonId(aliPayResource.getPayeeLogonId());
        entity.setPayeeUserId(aliPayResource.getPayeeUserId());
        entity.setFreezeNotifyUrl(aliPayResource.getFreezeNotifyUrl());
        entity.setServiceId(aliPayResource.getServiceId());
        return entity;
    }


    /**
     * 支付宝支付回调
     * min/ali/notify/order
     *
     * @param request
     * @return
     */
    @RequestMapping("/notify/order")
    public String callback(HttpServletRequest request) {
        Map<String, String> params = convertRequestParamsToMap(request); // 将异步通知中收到的待验证所有参数都存放到map中
        String paramsJson = JSON.toJSONString(params);
        logger.info("支付宝支付回调，{}", paramsJson);
        try {
            String out_trade_no = params.get("out_trade_no");
            // 查询对应支付订单
            Order order = orderService.selectByOutTradeNo(out_trade_no);
            if (order == null) {
                logger.info("获取订单失败[" + out_trade_no + "]");
                return "failure";
            }

            if (OrderTradeStateEnum.PAY_SUCCESS.getCode().intValue() == order.getTradeState().intValue()) {
                // 订单支付成功
                logger.info("支付宝支付订单[" + out_trade_no + "]已处理完毕");
                return "success";
            }

            if (OrderTradeStateEnum.UNPAID.getCode().intValue() != order.getTradeState().intValue()) {
                logger.info("支付宝支付订单[" + out_trade_no + "]处于其他状态" + order.getTradeState());
                return "success";
            }

            // 查询支付订单是否已支付
            AliPayEntity entity = _callApi();
            BatteryJSONResult queryResponse = AliPayUtils.tradeQuery(entity, out_trade_no);
            if (queryResponse.getCode() == 0) {
                String body = (String) queryResponse.getData();
                logger.info("查询支付宝支付订单失败,失败原因->[" + body + "]");
            }
            AlipayTradeQueryResponse response = (AlipayTradeQueryResponse) queryResponse.getData();
            String queryTradeStatus = response.getTradeStatus();
            // 支付宝支付回调处理
            return orderService.aliPayNotifyOrder(order, queryTradeStatus);
        } catch (Exception e) {
            e.printStackTrace();
            return "failure";
        }
    }


    /**
     * 支付宝授权资金冻结 回调
     *
     * @param request
     * @return
     */
    @RequestMapping("/notify/freeze")
    public String freezeCallback(HttpServletRequest request) {
        Map<String, String> params = convertRequestParamsToMap(request); // 将异步通知中收到的待验证所有参数都存放到map中
        String paramsJson = JSON.toJSONString(params);
        logger.info("支付宝授权资金冻结，{}", paramsJson);

        // 资金预授权冻结成功
        String status = params.get("status");
        if ("SUCCESS".equals(status)) {
            String out_order_no = params.get("out_order_no");
            String out_request_no = params.get("out_request_no");

            AuthUsed authUsed = authUsedService.selectByOutOrderNo(out_order_no);
            if (authUsed == null) {
                return "fail";
            }

            AliPayEntity entity = _callApi();
            JSONObject requestQueryObj = new JSONObject();
            requestQueryObj.put("out_order_no", out_order_no);
            requestQueryObj.put("out_request_no", out_request_no);
            BatteryJSONResult result = AliPayUtils.fundAuthQuery(entity, requestQueryObj, 1);
            if (result.getCode().intValue() == 0) {
                return "fail";
            }
            AlipayFundAuthOperationDetailQueryResponse response = (AlipayFundAuthOperationDetailQueryResponse) result.getData();
            String responseStatus = response.getStatus();
            BigDecimal totalFreezeAmount = new BigDecimal(response.getTotalFreezeAmount());
            if (totalFreezeAmount.subtract(new BigDecimal(0.01)).compareTo(BigDecimal.ZERO) >= 0 && "SUCCESS".equals(responseStatus)) {
                return authUsedService.freezeCallback(authUsed, response);
            }
        }
        return "success";
    }

    /**
     * 授权转支付 回调接口
     *
     * @param request
     * @return
     */
    @RequestMapping("/notify/freezePay")
    public String freezePay(HttpServletRequest request) {
        Map<String, String> params = convertRequestParamsToMap(request); // 将异步通知中收到的待验证所有参数都存放到map中
        String paramsJson = JSON.toJSONString(params);
        logger.info("支付宝授权转支付回调，{}", paramsJson);

        // tradeStatus.TRADE_SUCCESS 支付成功
        String trade_status = params.get("trade_status");
        if (!"TRADE_SUCCESS".equals(trade_status)) {
            return "fail";
        }

        String out_trade_no = params.get("out_trade_no");
        Order order = orderService.selectByOutTradeNo(out_trade_no);
        if (order == null) {
            return "fail";
        }

        if (OrderTradeStateEnum.PAY_SUCCESS.getCode().intValue() == order.getTradeState().intValue()) {
            // 订单支付成功
            logger.info("[授权转支付]支付宝支付订单[" + out_trade_no + "]已处理完毕");
            return "success";
        }


        if (OrderTradeStateEnum.UNPAID.getCode().intValue() != order.getTradeState().intValue()) {
            logger.info("支付宝支付订单[" + out_trade_no + "]处于其他状态" + order.getTradeState());
            return "success";
        }


        AuthUsed authUsed = authUsedService.selectByPrimaryKey(order.getUsedId());
        if (authUsed == null) {
            logger.info("[授权转支付]支付宝支付订单[" + out_trade_no + "]未查询到对应授权租借订单");
            return "fail";
        }

        return orderService.aliFreezePayNotify(order, authUsed, params);
    }


    /**
     * 将request中的参数转换成Map
     *
     * @param request
     * @return
     */
    private static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
        Map<String, String> retMap = new HashMap<String, String>();
        Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();
        for (Map.Entry<String, String[]> entry : entrySet) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            int valLen = values.length;
            if (valLen == 1) {
                retMap.put(name, values[0]);
            } else if (valLen > 1) {
                StringBuilder sb = new StringBuilder();
                for (String val : values) {
                    sb.append(",").append(val);
                }
                retMap.put(name, sb.toString().substring(1));
            } else {
                retMap.put(name, "");
            }
        }
        return retMap;
    }


}
